package com.utils

import com.entity.PackPath
import org.apache.logging.log4j.kotlin.logger
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentSkipListMap
import kotlin.io.path.*

class PropertiesUtils {

    companion object {
        val instance by lazy { PropertiesUtils() }
        private val PATH_SPLIT_REGEX = "[/\\\\]".toRegex()
    }

    var inputPath: Path? = null
        private set

    private val splitListCache by lazy { ConcurrentHashMap<String, List<String>>() }
    private val cacheMap: ConcurrentSkipListMap<String, String> by lazy {
        ConcurrentSkipListMap<String, String> { o1, o2 ->
            if (o1 == o2) return@ConcurrentSkipListMap 0
            val components1 = splitListCache.getOrPut(o1) { o1.split(PATH_SPLIT_REGEX) }
            val components2 = splitListCache.getOrPut(o2) { o2.split(PATH_SPLIT_REGEX) }
            val minSize = minOf(components1.size, components2.size)
            for (i in 0 until minSize) {
                val cmp = components1[i].compareTo(components2[i])
                if (cmp != 0) return@ConcurrentSkipListMap cmp
            }
            components1.size.compareTo(components2.size)
        }
    }

    fun read(path: String, autoCreate: Boolean = true) {
        read(Path(path), autoCreate)
    }

    fun read(path: Path, autoCreate: Boolean = true) {
        this.inputPath = path
        if (autoCreate) {
            if (!path.exists()) {
                store()
            }
        }
        path.readLines().mapNotNull {
            val a = it.split("=")
            if (a.size == 2) {
                a[0] to a[1]
            } else null
        }.toMap(cacheMap)

        // 通配符判断
        if (cacheMap.isNotEmpty()) {
            // 旧版未处理的路径
            val oldKey = keySet().filter { it.contains("\\") }
            if (oldKey.isNotEmpty()) {
                oldKey.forEach {
                    val content = get(it)
                    remove(it)
                    add(it.replace("\\", "/"), content)
                }
            }
        }
    }

    fun containsKey(path: PackPath): Boolean {
        return containsKey(path.absolutePathString)
    }

    fun containsKey(key: String): Boolean {
        return cacheMap.containsKey(key)
    }

    fun keySet(): Set<String> {
        return cacheMap.keys.toSet()
    }

    fun size(): Int {
        return cacheMap.size
    }

    fun clear() {
        cacheMap.clear()
    }

    fun remove(path: PackPath, autoSave: Boolean = false) {
        remove(path.absolutePathString, autoSave)
    }

    fun remove(key: String, autoSave: Boolean = false) {
        cacheMap.remove(key)
        splitListCache.remove(key)
        if (autoSave) {
            store()
        }
    }

    val pathToString: String
        get() {
            return inputPath?.pathString ?: ""
        }

    fun add(path: PackPath, value: String?, autoSave: Boolean = false) {
        add(path.absolutePathString, value, autoSave)
    }

    fun add(key: String?, value: String?, autoSave: Boolean = false) {
        if (key == null) return
        if (value == null) error("value 不能是null")
        runCatching {
            val path = key.replace("\\", "/")
            cacheMap[path] = value
            if (autoSave) {
                store()
            }
        }.onFailure {
            logger.error("", it)
        }
    }

    fun get(path: PackPath): String? {
        return get(path.absolutePathString)
    }

    fun get(key: String): String? {
        return cacheMap[key]
    }

    fun store() {
        if (inputPath != null) {
            inputPath!!.createParentDirectories()
            val list = cacheMap.map { (key, value) -> "$key=$value" }
            inputPath!!.writeText(list.joinToString("\n"))
        }
    }

}
